{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 12.12 \u4f7f\u7528\u751f\u6210\u5668\u4ee3\u66ff\u7ebf\u7a0b\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u60f3\u4f7f\u7528\u751f\u6210\u5668\uff08\u534f\u7a0b\uff09\u66ff\u4ee3\u7cfb\u7edf\u7ebf\u7a0b\u6765\u5b9e\u73b0\u5e76\u53d1\u3002\u8fd9\u4e2a\u6709\u65f6\u53c8\u88ab\u79f0\u4e3a\u7528\u6237\u7ea7\u7ebf\u7a0b\u6216\u7eff\u8272\u7ebf\u7a0b\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8981\u4f7f\u7528\u751f\u6210\u5668\u5b9e\u73b0\u81ea\u5df1\u7684\u5e76\u53d1\uff0c\u4f60\u9996\u5148\u8981\u5bf9\u751f\u6210\u5668\u51fd\u6570\u548c yield \u8bed\u53e5\u6709\u6df1\u523b\u7406\u89e3\u3002\nyield \u8bed\u53e5\u4f1a\u8ba9\u4e00\u4e2a\u751f\u6210\u5668\u6302\u8d77\u5b83\u7684\u6267\u884c\uff0c\u8fd9\u6837\u5c31\u53ef\u4ee5\u7f16\u5199\u4e00\u4e2a\u8c03\u5ea6\u5668\uff0c\n\u5c06\u751f\u6210\u5668\u5f53\u505a\u67d0\u79cd\u201c\u4efb\u52a1\u201d\u5e76\u4f7f\u7528\u4efb\u52a1\u534f\u4f5c\u5207\u6362\u6765\u66ff\u6362\u5b83\u4eec\u7684\u6267\u884c\u3002\n\u8981\u6f14\u793a\u8fd9\u79cd\u601d\u60f3\uff0c\u8003\u8651\u4e0b\u9762\u4e24\u4e2a\u4f7f\u7528\u7b80\u5355\u7684 yield \u8bed\u53e5\u7684\u751f\u6210\u5668\u51fd\u6570\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Two simple generator functions\ndef countdown(n):\n    while n > 0:\n        print('T-minus', n)\n        yield\n        n -= 1\n    print('Blastoff!')\n\ndef countup(n):\n    x = 0\n    while x < n:\n        print('Counting up', x)\n        yield\n        x += 1"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd9\u4e9b\u51fd\u6570\u5728\u5185\u90e8\u4f7f\u7528yield\u8bed\u53e5\uff0c\u4e0b\u9762\u662f\u4e00\u4e2a\u5b9e\u73b0\u4e86\u7b80\u5355\u4efb\u52a1\u8c03\u5ea6\u5668\u7684\u4ee3\u7801\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from collections import deque\n\nclass TaskScheduler:\n    def __init__(self):\n        self._task_queue = deque()\n\n    def new_task(self, task):\n        '''\n        Admit a newly started task to the scheduler\n        '''\n        self._task_queue.append(task)\n\n    def run(self):\n        '''\n        Run until there are no more tasks\n        '''\n        while self._task_queue:\n            task = self._task_queue.popleft()\n            try:\n                # Run until the next yield statement\n                next(task)\n                self._task_queue.append(task)\n            except StopIteration:\n                # Generator is no longer executing\n                pass\n\n# Example use\nsched = TaskScheduler()\nsched.new_task(countdown(10))\nsched.new_task(countdown(5))\nsched.new_task(countup(15))\nsched.run()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "TaskScheduler \u7c7b\u5728\u4e00\u4e2a\u5faa\u73af\u4e2d\u8fd0\u884c\u751f\u6210\u5668\u96c6\u5408\u2014\u2014\u6bcf\u4e2a\u90fd\u8fd0\u884c\u5230\u78b0\u5230yield\u8bed\u53e5\u4e3a\u6b62\u3002\n\u8fd0\u884c\u8fd9\u4e2a\u4f8b\u5b50\uff0c\u8f93\u51fa\u5982\u4e0b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "T-minus 10\nT-minus 5\nCounting up 0\nT-minus 9\nT-minus 4\nCounting up 1\nT-minus 8\nT-minus 3\nCounting up 2\nT-minus 7\nT-minus 2\n..."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5230\u6b64\u4e3a\u6b62\uff0c\u6211\u4eec\u5b9e\u9645\u4e0a\u5df2\u7ecf\u5b9e\u73b0\u4e86\u4e00\u4e2a\u201c\u64cd\u4f5c\u7cfb\u7edf\u201d\u7684\u6700\u5c0f\u6838\u5fc3\u90e8\u5206\u3002\n\u751f\u6210\u5668\u51fd\u6570\u5c31\u662f\u4efb\u52a1\uff0c\u800cyield\u8bed\u53e5\u662f\u4efb\u52a1\u6302\u8d77\u7684\u4fe1\u53f7\u3002\n\u8c03\u5ea6\u5668\u5faa\u73af\u68c0\u67e5\u4efb\u52a1\u5217\u8868\u76f4\u5230\u6ca1\u6709\u4efb\u52a1\u8981\u6267\u884c\u4e3a\u6b62\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5b9e\u9645\u4e0a\uff0c\u4f60\u53ef\u80fd\u60f3\u8981\u4f7f\u7528\u751f\u6210\u5668\u6765\u5b9e\u73b0\u7b80\u5355\u7684\u5e76\u53d1\u3002\n\u90a3\u4e48\uff0c\u5728\u5b9e\u73b0actor\u6216\u7f51\u7edc\u670d\u52a1\u5668\u7684\u65f6\u5019\u4f60\u53ef\u4ee5\u4f7f\u7528\u751f\u6210\u5668\u6765\u66ff\u4ee3\u7ebf\u7a0b\u7684\u4f7f\u7528\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e0b\u9762\u7684\u4ee3\u7801\u6f14\u793a\u4e86\u4f7f\u7528\u751f\u6210\u5668\u6765\u5b9e\u73b0\u4e00\u4e2a\u4e0d\u4f9d\u8d56\u7ebf\u7a0b\u7684actor\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from collections import deque\n\nclass ActorScheduler:\n    def __init__(self):\n        self._actors = {}          # Mapping of names to actors\n        self._msg_queue = deque()   # Message queue\n\n    def new_actor(self, name, actor):\n        '''\n        Admit a newly started actor to the scheduler and give it a name\n        '''\n        self._msg_queue.append((actor,None))\n        self._actors[name] = actor\n\n    def send(self, name, msg):\n        '''\n        Send a message to a named actor\n        '''\n        actor = self._actors.get(name)\n        if actor:\n            self._msg_queue.append((actor,msg))\n\n    def run(self):\n        '''\n        Run as long as there are pending messages.\n        '''\n        while self._msg_queue:\n            actor, msg = self._msg_queue.popleft()\n            try:\n                 actor.send(msg)\n            except StopIteration:\n                 pass\n\n# Example use\nif __name__ == '__main__':\n    def printer():\n        while True:\n            msg = yield\n            print('Got:', msg)\n\n    def counter(sched):\n        while True:\n            # Receive the current count\n            n = yield\n            if n == 0:\n                break\n            # Send to the printer task\n            sched.send('printer', n)\n            # Send the next count to the counter task (recursive)\n            sched.send('counter', n-1)\n\n    sched = ActorScheduler()\n    # Create the initial actors\n    sched.new_actor('printer', printer())\n    sched.new_actor('counter', counter(sched))\n\n    # Send an initial message to the counter to initiate\n    sched.send('counter', 10000)\n    sched.run()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5b8c\u5168\u5f04\u61c2\u8fd9\u6bb5\u4ee3\u7801\u9700\u8981\u66f4\u6df1\u5165\u7684\u5b66\u4e60\uff0c\u4f46\u662f\u5173\u952e\u70b9\u5728\u4e8e\u6536\u96c6\u6d88\u606f\u7684\u961f\u5217\u3002\n\u672c\u8d28\u4e0a\uff0c\u8c03\u5ea6\u5668\u5728\u6709\u9700\u8981\u53d1\u9001\u7684\u6d88\u606f\u65f6\u4f1a\u4e00\u76f4\u8fd0\u884c\u7740\u3002\n\u8ba1\u6570\u751f\u6210\u5668\u4f1a\u7ed9\u81ea\u5df1\u53d1\u9001\u6d88\u606f\u5e76\u5728\u4e00\u4e2a\u9012\u5f52\u5faa\u73af\u4e2d\u7ed3\u675f\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e0b\u9762\u662f\u4e00\u4e2a\u66f4\u52a0\u9ad8\u7ea7\u7684\u4f8b\u5b50\uff0c\u6f14\u793a\u4e86\u4f7f\u7528\u751f\u6210\u5668\u6765\u5b9e\u73b0\u4e00\u4e2a\u5e76\u53d1\u7f51\u7edc\u5e94\u7528\u7a0b\u5e8f\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from collections import deque\nfrom select import select\n\n# This class represents a generic yield event in the scheduler\nclass YieldEvent:\n    def handle_yield(self, sched, task):\n        pass\n\n    def handle_resume(self, sched, task):\n        pass\n\n# Task Scheduler\nclass Scheduler:\n    def __init__(self):\n        self._numtasks = 0       # Total num of tasks\n        self._ready = deque()    # Tasks ready to run\n        self._read_waiting = {}  # Tasks waiting to read\n        self._write_waiting = {} # Tasks waiting to write\n\n    # Poll for I/O events and restart waiting tasks\n    def _iopoll(self):\n        rset,wset,eset = select(self._read_waiting,\n                                self._write_waiting,[])\n        for r in rset:\n            evt, task = self._read_waiting.pop(r)\n            evt.handle_resume(self, task)\n        for w in wset:\n            evt, task = self._write_waiting.pop(w)\n            evt.handle_resume(self, task)\n\n    def new(self,task):\n        '''\n        Add a newly started task to the scheduler\n        '''\n        self._ready.append((task, None))\n        self._numtasks += 1\n\n    def add_ready(self, task, msg=None):\n        '''\n        Append an already started task to the ready queue.\n        msg is what to send into the task when it resumes.\n        '''\n        self._ready.append((task, msg))\n\n    # Add a task to the reading set\n    def _read_wait(self, fileno, evt, task):\n        self._read_waiting[fileno] = (evt, task)\n\n    # Add a task to the write set\n    def _write_wait(self, fileno, evt, task):\n        self._write_waiting[fileno] = (evt, task)\n\n    def run(self):\n        '''\n        Run the task scheduler until there are no tasks\n        '''\n        while self._numtasks:\n             if not self._ready:\n                  self._iopoll()\n             task, msg = self._ready.popleft()\n             try:\n                 # Run the coroutine to the next yield\n                 r = task.send(msg)\n                 if isinstance(r, YieldEvent):\n                     r.handle_yield(self, task)\n                 else:\n                     raise RuntimeError('unrecognized yield event')\n             except StopIteration:\n                 self._numtasks -= 1\n\n# Example implementation of coroutine-based socket I/O\nclass ReadSocket(YieldEvent):\n    def __init__(self, sock, nbytes):\n        self.sock = sock\n        self.nbytes = nbytes\n    def handle_yield(self, sched, task):\n        sched._read_wait(self.sock.fileno(), self, task)\n    def handle_resume(self, sched, task):\n        data = self.sock.recv(self.nbytes)\n        sched.add_ready(task, data)\n\nclass WriteSocket(YieldEvent):\n    def __init__(self, sock, data):\n        self.sock = sock\n        self.data = data\n\n    def handle_yield(self, sched, task):\n        sched._write_wait(self.sock.fileno(), self, task)\n\n    def handle_resume(self, sched, task):\n        nsent = self.sock.send(self.data)\n        sched.add_ready(task, nsent)\n\nclass AcceptSocket(YieldEvent):\n    def __init__(self, sock):\n        self.sock = sock\n\n    def handle_yield(self, sched, task):\n        sched._read_wait(self.sock.fileno(), self, task)\n\n    def handle_resume(self, sched, task):\n        r = self.sock.accept()\n        sched.add_ready(task, r)\n\n# Wrapper around a socket object for use with yield\nclass Socket(object):\n    def __init__(self, sock):\n        self._sock = sock\n\n    def recv(self, maxbytes):\n        return ReadSocket(self._sock, maxbytes)\n\n    def send(self, data):\n        return WriteSocket(self._sock, data)\n\n    def accept(self):\n        return AcceptSocket(self._sock)\n\n    def __getattr__(self, name):\n        return getattr(self._sock, name)\n\nif __name__ == '__main__':\n    from socket import socket, AF_INET, SOCK_STREAM\n    import time\n\n    # Example of a function involving generators.  This should\n    # be called using line = yield from readline(sock)\n    def readline(sock):\n        chars = []\n        while True:\n            c = yield sock.recv(1)\n            if not c:\n                break\n            chars.append(c)\n            if c == b'\\n':\n                break\n        return b''.join(chars)\n\n    # Echo server using generators\n    class EchoServer:\n        def __init__(self,addr,sched):\n            self.sched = sched\n            sched.new(self.server_loop(addr))\n\n        def server_loop(self,addr):\n            s = Socket(socket(AF_INET,SOCK_STREAM))\n\n            s.bind(addr)\n            s.listen(5)\n            while True:\n                c,a = yield s.accept()\n                print('Got connection from ', a)\n                self.sched.new(self.client_handler(Socket(c)))\n\n        def client_handler(self,client):\n            while True:\n                line = yield from readline(client)\n                if not line:\n                    break\n                line = b'GOT:' + line\n                while line:\n                    nsent = yield client.send(line)\n                    line = line[nsent:]\n            client.close()\n            print('Client closed')\n\n    sched = Scheduler()\n    EchoServer(('',16000),sched)\n    sched.run()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd9\u6bb5\u4ee3\u7801\u6709\u70b9\u590d\u6742\u3002\u4e0d\u8fc7\uff0c\u5b83\u5b9e\u73b0\u4e86\u4e00\u4e2a\u5c0f\u578b\u7684\u64cd\u4f5c\u7cfb\u7edf\u3002\n\u6709\u4e00\u4e2a\u5c31\u7eea\u7684\u4efb\u52a1\u961f\u5217\uff0c\u5e76\u4e14\u8fd8\u6709\u56e0I/O\u4f11\u7720\u7684\u4efb\u52a1\u7b49\u5f85\u533a\u57df\u3002\n\u8fd8\u6709\u5f88\u591a\u8c03\u5ea6\u5668\u8d1f\u8d23\u5728\u5c31\u7eea\u961f\u5217\u548cI/O\u7b49\u5f85\u533a\u57df\u4e4b\u95f4\u79fb\u52a8\u4efb\u52a1\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728\u6784\u5efa\u57fa\u4e8e\u751f\u6210\u5668\u7684\u5e76\u53d1\u6846\u67b6\u65f6\uff0c\u901a\u5e38\u4f1a\u4f7f\u7528\u66f4\u5e38\u89c1\u7684yield\u5f62\u5f0f\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "def some_generator():\n    ...\n    result = yield data\n    ..."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f7f\u7528\u8fd9\u79cd\u5f62\u5f0f\u7684yield\u8bed\u53e5\u7684\u51fd\u6570\u901a\u5e38\u88ab\u79f0\u4e3a\u201c\u534f\u7a0b\u201d\u3002\n\u901a\u8fc7\u8c03\u5ea6\u5668\uff0cyield\u8bed\u53e5\u5728\u4e00\u4e2a\u5faa\u73af\u4e2d\u88ab\u5904\u7406\uff0c\u5982\u4e0b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "f = some_generator()\n\n# Initial result. Is None to start since nothing has been computed\nresult = None\nwhile True:\n    try:\n        data = f.send(result)\n        result = ... do some calculation ...\n    except StopIteration:\n        break"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd9\u91cc\u7684\u903b\u8f91\u7a0d\u5fae\u6709\u70b9\u590d\u6742\u3002\u4e0d\u8fc7\uff0c\u88ab\u4f20\u7ed9 send() \u7684\u503c\u5b9a\u4e49\u4e86\u5728yield\u8bed\u53e5\u9192\u6765\u65f6\u7684\u8fd4\u56de\u503c\u3002\n\u56e0\u6b64\uff0c\u5982\u679c\u4e00\u4e2ayield\u51c6\u5907\u5728\u5bf9\u4e4b\u524dyield\u6570\u636e\u7684\u56de\u5e94\u4e2d\u8fd4\u56de\u7ed3\u679c\u65f6\uff0c\u4f1a\u5728\u4e0b\u4e00\u6b21 send() \u64cd\u4f5c\u8fd4\u56de\u3002\n\u5982\u679c\u4e00\u4e2a\u751f\u6210\u5668\u51fd\u6570\u521a\u5f00\u59cb\u8fd0\u884c\uff0c\u53d1\u9001\u4e00\u4e2aNone\u503c\u4f1a\u8ba9\u5b83\u6392\u5728\u7b2c\u4e00\u4e2ayield\u8bed\u53e5\u524d\u9762\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u9664\u4e86\u53d1\u9001\u503c\u5916\uff0c\u8fd8\u53ef\u4ee5\u5728\u4e00\u4e2a\u751f\u6210\u5668\u4e0a\u9762\u6267\u884c\u4e00\u4e2a close() \u65b9\u6cd5\u3002\n\u5b83\u4f1a\u5bfc\u81f4\u5728\u6267\u884cyield\u8bed\u53e5\u65f6\u629b\u51fa\u4e00\u4e2a GeneratorExit \u5f02\u5e38\uff0c\u4ece\u800c\u7ec8\u6b62\u6267\u884c\u3002\n\u5982\u679c\u8fdb\u4e00\u6b65\u8bbe\u8ba1\uff0c\u4e00\u4e2a\u751f\u6210\u5668\u53ef\u4ee5\u6355\u83b7\u8fd9\u4e2a\u5f02\u5e38\u5e76\u6267\u884c\u6e05\u7406\u64cd\u4f5c\u3002\n\u540c\u6837\u8fd8\u53ef\u4ee5\u4f7f\u7528\u751f\u6210\u5668\u7684 throw() \u65b9\u6cd5\u5728yield\u8bed\u53e5\u6267\u884c\u65f6\u751f\u6210\u4e00\u4e2a\u4efb\u610f\u7684\u6267\u884c\u6307\u4ee4\u3002\n\u4e00\u4e2a\u4efb\u52a1\u8c03\u5ea6\u5668\u53ef\u5229\u7528\u5b83\u6765\u5728\u8fd0\u884c\u7684\u751f\u6210\u5668\u4e2d\u5904\u7406\u9519\u8bef\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6700\u540e\u4e00\u4e2a\u4f8b\u5b50\u4e2d\u4f7f\u7528\u7684 yield from \u8bed\u53e5\u88ab\u7528\u6765\u5b9e\u73b0\u534f\u7a0b\uff0c\u53ef\u4ee5\u88ab\u5176\u5b83\u751f\u6210\u5668\u4f5c\u4e3a\u5b50\u7a0b\u5e8f\u6216\u8fc7\u7a0b\u6765\u8c03\u7528\u3002\n\u672c\u8d28\u4e0a\u5c31\u662f\u5c06\u63a7\u5236\u6743\u900f\u660e\u7684\u4f20\u8f93\u7ed9\u65b0\u7684\u51fd\u6570\u3002\n\u4e0d\u50cf\u666e\u901a\u7684\u751f\u6210\u5668\uff0c\u4e00\u4e2a\u4f7f\u7528 yield from \u88ab\u8c03\u7528\u7684\u51fd\u6570\u53ef\u4ee5\u8fd4\u56de\u4e00\u4e2a\u4f5c\u4e3a yield from \u8bed\u53e5\u7ed3\u679c\u7684\u503c\u3002\n\u5173\u4e8e yield from \u7684\u66f4\u591a\u4fe1\u606f\u53ef\u4ee5\u5728 PEP 380 \u4e2d\u627e\u5230\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6700\u540e\uff0c\u5982\u679c\u4f7f\u7528\u751f\u6210\u5668\u7f16\u7a0b\uff0c\u8981\u63d0\u9192\u4f60\u7684\u662f\u5b83\u8fd8\u662f\u6709\u5f88\u591a\u7f3a\u70b9\u7684\u3002\n\u7279\u522b\u662f\uff0c\u4f60\u5f97\u4e0d\u5230\u4efb\u4f55\u7ebf\u7a0b\u53ef\u4ee5\u63d0\u4f9b\u7684\u597d\u5904\u3002\u4f8b\u5982\uff0c\u5982\u679c\u4f60\u6267\u884cCPU\u4f9d\u8d56\u6216I/O\u963b\u585e\u7a0b\u5e8f\uff0c\n\u5b83\u4f1a\u5c06\u6574\u4e2a\u4efb\u52a1\u6302\u8d77\u76f4\u5230\u64cd\u4f5c\u5b8c\u6210\u3002\u4e3a\u4e86\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\uff0c\n\u4f60\u53ea\u80fd\u9009\u62e9\u5c06\u64cd\u4f5c\u59d4\u6d3e\u7ed9\u53e6\u5916\u4e00\u4e2a\u53ef\u4ee5\u72ec\u7acb\u8fd0\u884c\u7684\u7ebf\u7a0b\u6216\u8fdb\u7a0b\u3002\n\u53e6\u5916\u4e00\u4e2a\u9650\u5236\u662f\u5927\u90e8\u5206Python\u5e93\u5e76\u4e0d\u80fd\u5f88\u597d\u7684\u517c\u5bb9\u57fa\u4e8e\u751f\u6210\u5668\u7684\u7ebf\u7a0b\u3002\n\u5982\u679c\u4f60\u9009\u62e9\u8fd9\u4e2a\u65b9\u6848\uff0c\u4f60\u4f1a\u53d1\u73b0\u4f60\u9700\u8981\u81ea\u5df1\u6539\u5199\u5f88\u591a\u6807\u51c6\u5e93\u51fd\u6570\u3002\n\u4f5c\u4e3a\u672c\u8282\u63d0\u5230\u7684\u534f\u7a0b\u548c\u76f8\u5173\u6280\u672f\u7684\u4e00\u4e2a\u57fa\u7840\u80cc\u666f\uff0c\u53ef\u4ee5\u67e5\u770b PEP 342\n\u548c \u201c\u534f\u7a0b\u548c\u5e76\u53d1\u7684\u4e00\u95e8\u6709\u8da3\u8bfe\u7a0b\u201d"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "PEP 3156 \u540c\u6837\u6709\u4e00\u4e2a\u5173\u4e8e\u4f7f\u7528\u534f\u7a0b\u7684\u5f02\u6b65I/O\u6a21\u578b\u3002\n\u7279\u522b\u7684\uff0c\u4f60\u4e0d\u53ef\u80fd\u81ea\u5df1\u53bb\u5b9e\u73b0\u4e00\u4e2a\u5e95\u5c42\u7684\u534f\u7a0b\u8c03\u5ea6\u5668\u3002\n\u4e0d\u8fc7\uff0c\u5173\u4e8e\u534f\u7a0b\u7684\u601d\u60f3\u662f\u5f88\u591a\u6d41\u884c\u5e93\u7684\u57fa\u7840\uff0c\n\u5305\u62ec gevent,\ngreenlet,\nStackless Python \u4ee5\u53ca\u5176\u4ed6\u7c7b\u4f3c\u5de5\u7a0b\u3002"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.7.1"
    },
    "toc": {
      "base_numbering": 1,
      "nav_menu": {},
      "number_sections": true,
      "sideBar": true,
      "skip_h1_title": true,
      "title_cell": "Table of Contents",
      "title_sidebar": "Contents",
      "toc_cell": false,
      "toc_position": {},
      "toc_section_display": true,
      "toc_window_display": true
    }
  },
  "nbformat": 4,
  "nbformat_minor": 2
}